% !TEX root = ../main.tex

\chapter{架构与模块设计}

\section{需求分析}
在进行架构设计和具体的模块设计之前，先对需求进行分析和总结。
这一小节将分析需要完成哪些设计和模型，来实现和验证在CIS芯片上的基于脉动阵列的ResNet18硬件加速运算。


\subsection{基础设定}
%由于整个芯片的顶层架构设计非常复杂，工作量也十分庞大。
%而本文的研究课题是一种CIS片上的深度学习神经网络运算的设计和建模。
%因此，这里可以做一些假设来代替非核心内容的设计工作。  

%首先，我们先假设使用的CPU、总线、DRAM、SRAM都是理想状态。
在本课题中，首先需要设计CIS芯片的基础架构。
CIS芯片的基础架构包括了CPU、总线、ROM、SRAM、DRAM以及图像数据信号通路上的各个模块。
CPU和总线是芯片上必不可少的设备。
但本课题中的深度学习算法的运算将全部由专门的硬件加速部件来完成运算，
因此下文将不再讨论CPU和总线的类型和设计。
关于存储设备，本课题将讨论选用存储器的种类和不同种类存储器所需要的存储大小。
因为通常在一些小型的CIS中，芯片所需的内存很少，所以只需要选用SRAM就可以满足系统的需要。
在考虑到深度学习神经网络的模型的大小，同时也参考了一些业内的深度学习神经网络运算专用芯片，本课题中的设计将同时使用SRAM和DRAM。

% 内存大小的设计

\subsection{详细需求}
%讨论详细需求。
% 用例

% 需求分析
因此，我们可以分解需求，并得到以下列出的需求点：
\begin{enumerate}
    \item CIS的基础模块
    \item 图像处理模块
    \item 脉动阵列的设计
    \item ResNet18在脉动阵列上的实现
\end{enumerate}    

对于图像处理模块，需要设计一个配合脉动阵列工作的数据信号输入模块。
这个模块需要根据后文描述的脉动阵列运算的行为，将视频数据流中的数据按照脉动阵列所需的顺序放置到脉动阵列的输入缓冲中。
在脉动阵列中，需要设计每个处理单元的逻辑和工作行为。
在实现神经网络算法时，需要分解出所有使用到的运算符，并分析哪些可以通过脉动阵列的乘加运算矩阵加速。

\subsubsection{ResNet18中的基本运算}
选择ResNet18在此设计中实现的主要原因是ResNet18结构简单且图像识别正确率出众。
除了一开始的7x7卷积核，在实现运算的BasicBlock中的卷积运算全部采用的3x3的卷积核。
这样既可以把如何进行卷积运算的设计表达清楚，也可以避免过多地描述卷积神经网络算法本身。

% TODO 简述ResNet18的网络结构
ResNet18由4个主要的残差层组成。
整个网络的开头，由7x7的卷积核做卷积运算和3x3的最大池化。
卷积运算有64个输出的通道。设定的步长是2，填充的边框是3。
最大值池化的步长是2，填充的边框是1。
最后输出的图像尺寸是112x112

之后是四个包含两个BasicBlock来做运算的残差层。
每个BasicBlock中都有两个3x3的卷积运算。
它们的深度不同，分别是64、128、256和512。
ResNet可能使用两种不同的残差单元。一种是BasicBlock，用于ResNet18和ResNet34这种浅层网络。
另一种是Bottleneck，用于50层及以上的ResNet。

第一个残差层的卷积运算有64个输出通道。其输出的图像尺寸是56x56。
第二个残差层的卷积运算有128个输出通道。其中输出的图像尺寸是28x28。
第三个残差层的卷积运算有256个输出通道。其中输出的图像尺寸是14x14。
第四个残差层的卷积运算有512个输出通道。其中输出的图像尺寸是7x7。
最后，以平均池化、全连接和softmax结束整个resnet18网络。

% TODO 展开7x7卷积运算。
% TODO 

将特征图经过批归一化和Relu()激活函数。这两个运算不会改变特征图的维度。
% TODO 展开BN和Relu激活函数

之后用3x3的卷积核将特征图进行最大池化，步长为2，边框填充为3，得到56x56x64的特征图。
% TODO 展开3x3的maxpooling

后面就开始将数据依次输入4个残差层。
% TODO 展开残差层的计算
残差层包含了两个BasicBlock。因此它的运算可以参考上面的代码段中BasicBlock类的内容。
首先，输入从上一层得到的56x56x64的特征图。
将这个特征图用3x3x64的卷积核做卷积运算。使用的步长为1，填充的边框为1，得到56x56x64的特征图输出。
假设输入的特征图大小为m，卷积核大小为x，步长为s，边框填充层数为p，那么输出的特征图大小 $m^{'}$ 由公式(2-1)计算得到：
\begin{equation}
m^{'} = \frac{( m + 2 \times p - x )}{s} + 1 
\end{equation}  


下面是ResNet18所涉及到的所有运算：
\begin{enumerate}
    \item 2D卷积运算
    \item 批归一化
    \item 最大值池化
    \item Relu()激活函数
    \item 平均值池化
    \item 全连接
\end{enumerate}


\section{总体架构设计}
CIS的顶层架构设计是由CPU、高速总线、存储以及数据通路上的各个外设组成。
在后续的讨论中，将会把CPU、高速总线、存储器等基础组件做为设计内容中的一些设定。
本文将假设输入到深度学习运算模块的数据流，是一种理想的图像数据。
对于CIS上深度学习运算模块的设计，我们首先可以参考ISP芯片的设计逻辑。
因为我们可以将深度学习运算模块也视作一种图像处理的模块。

从图\ref{fig:top_arch}中可以看到，这是图像传感器与ISP以及其他功能部件连接在一条高速数据总线的结构。
总体架构可以分为几个部分：数据通路部分、系统控制部分和高速数据总线。
数据通路部分包含了IDA(Input Data Adapter)、深度学习神经网络加速模块、TX输出模块。
系统控制部分包含了CPU、DMA、Memory、SPI Flash以及其他外设模块（比如$I^2C$和UART等接口模块）。
%TODO 架构图展示
\begin{figure}[htbp]
    \centering
    \includegraphics[width=15cm,height=6cm]{figures/top_arch.png}
    \caption{总体架构图}
    \label{fig:top_arch}
\end{figure}
%TODO 各个模块的简述
这里的视频数据格式设定为RGB888。

\section{CIS数据通路}
%TODO 展示Stream datapath的传输方式 sof eof href
%TODO DL accelerator在数据通路中的作用
%TODO Fix Timing模块做数据同步，最后输出结果
CIS芯片的作用，就是将图像传感器接收到的信号，转为数字信号后传输给后端。
CIS芯片上图像数字信号所经过的所有模块连接起来就像是一条单向的通道。
一般的，我们称这些模块所组成的通道为数据通路。
图像数据通路一般由输入、数据处理和输出三个部分组成。
通常地，这三个部分也具有各自不同的时钟域。

%TODO 架构图展示
\begin{figure}[htbp]
    \centering
    \includegraphics[width=15cm,height=5cm]{figures/datapath.png}
    \caption{图像信号处理的数据流图}
    \label{fig:datapath}
\end{figure}

%TODO 这里先描述以下datapath，包括DI、DP、DO三个时钟域。
如图\ref{fig:datapath}所示，图像处理部件的前后分别需要设置两个不同的时钟域用于输入和输出图像数据的信号。
因此，我们在设计CIS的数据通路中的深度学习运算模块时，也需要做相同的设计。
将输入模块的图像数据信号按一定的顺序排列好，按照脉动阵列的特性以一定的方式依次输入到阵列中。


在输入时钟域中，RX模块接收从CMOS传感器输出的数据。
由一个缓冲区暂存数据，经过时钟同步和一些预处理后向后面的数据处理时钟域输出数据。
在数据处理的时钟域中，深度学习运算模块将进行推理操作。
在输出时钟域中，FT(fix timing)模块将调整输出的时钟频率.TX模块负责以指定格式输出图像数据。  

\subsection{数据流的输入}
% TODO 
%   数据流的输入将由IDA(Input Data Adapter)模块处理。这个模块的主要作用是将Sensor输出的数据放到一个缓存区。
%   并将视频数据流的plck同步到数据流的时钟域。

这里假设从图像传感器输出的图像数据为224x224像素尺寸的图像。
视频数据流的输入需要参考流式设备的特性，合理的缓存大小和同步的时机是关键点。
对于卷积运算，缓存的行数大小应该大于等于卷积核的行数和列数之间的较大值。
例如，卷积核的尺寸为3x3时，缓存至少要保存3行数据。
如果，每帧图像的尺寸为224x224个像素点。
由RGB三个通道组成的每一帧都拆分成三个224x224x8比特。
那么需要给一个通道的一帧数据缓存的大小需要大于等于672个字节。

\begin{figure}[htbp]
    \centering
    \includegraphics[width=12cm,height=8cm]{figures/input_data_adapter.png}
    \caption{输入数据同步单元架构图}
    \label{fig:input_data_adapter}
\end{figure}

上图\ref{fig:input_data_adapter}是数据输入同步单元与深度学习加速器之间的连线设计。
hsync用于行同步信号。
vsync用于帧同步信号。
pclk是像素时钟信号。
data是并行的图像数据，这里设定为8bit带宽。
SCL和SDA是用来读写模块寄存器的I2C接口的时钟信号和数据信号。


\subsection{数据流中的运算}
% TODO
% 在数据流中实时运算图像识别的算法

在数据通路中实时地进行图像识别的运算，是本设计的核心思想。
此设计选择了ResNet18作为实现的网络算法。
运算的模块将通过帧同步信号和行同步信号等机制来处理缓存的数据。
在实际应用时，将用于图像识别的人工智能处理器在物理位置上比较靠近图像来源（CMOS传感器），这样就避免了图像数据需要SRAM/DRAM的存储。
同时，还可以利用图像数据流的流水线特性，设计减小输入缓冲的图像输入模块。
依靠图像数据信号中的行同步信号和帧同步信号，来同步向数据通道后方的脉动阵列输送数据，那么就不需要缓冲多帧或者一个完整帧的数据。
另外，由于一般的CNN算法是共享权值的。这样权值的数量就不大，可以完整存放在片上SRAM中，从而使得读取权值的操作也能避免访问DRAM。
在设计权值缓冲区时，我们采用了Multi-bank的思想。将划分多个bank缓冲区，来分别缓冲不同卷积层的权值。
这样的话，权值缓冲区可以在脉动阵列工作时，加载后一层的权值到缓冲区中。
在需要进行下一层的运算时，脉动阵列就可以直接从SRAM的缓冲区中读取权值，而不是DRAM。
这样处理后，整个系统将大幅降低功耗。
% 单独画图解释一下权值缓冲区
% 单独画图解释一下行同步信号控制数据输入

整个深度学习加速器模块有2个缓存分别用于存储权值、输入数据。
核心的运算模块是由最小运算单元组成的脉动阵列。
普通的运算阵列受限于其规模。它的规模越大，需要的传输布线长度约长，传输时间越久，因此频率也无法做到很高。
这样的话，它的运算性能就会受到规模大小的限制。




\subsubsection{边框填充(padding)和数据输入}
对于边框填充，如果直接对输入数据进行修改，将会需要很大的存储来缓存数据，并且不排除会有很多读写的操作影响整个运算的效率。
因此，我们需要设计一个专门用于填充边框的模块。
让它在把数据送入脉动阵列的通道以前，加入对应的填充值。
在把数据送入脉动阵列时，需要将数据按照执行卷积运算时的顺序依次送入脉动阵列。
下图是一个对一个5x5的输入用2个3x3的卷积核做卷积运算的示意图，用来说明怎样对输入脉动阵列的数据进行排序和分组的。
图中，左侧的由两位数字组成的标号表示了它在5x5的矩阵中的位置。
右侧的两列分别是W0和W1的两个卷积核的数据平铺展开得到的。
0到8的编号表示了它们在两个卷积核中的位置。
%这里插入一个对一个5x5的输入用3x3的卷积核做卷积运算的示意图

\begin{figure}[htbp]
    \centering
    \includegraphics[width=15cm,height=7cm]{figures/input_systolic_array.png}
    \caption{数据输入脉动阵列示意图}
    \label{systolic}
\end{figure}


\subsubsection{脉动阵列}
在深度残差网络ResNet18中，由5个卷积层组成，除了第一个卷积层外，后4个卷积层都是由2个基础块组成。基础块的结构如下图x所示。其中的批量标准化和Relu函
数都可以设计专用的运算模块，而3x3的卷积运算可以通过脉动阵列来运算。 

% \begin{table}[!hpt]
%     \bicaption[PE的寄存器表]{PE的寄存器表}{Register Table Of PE}
%     \label{tab:firstone}
%     \centering
%     \begin{tabular}{@{}lllr@{}} \toprule
%         Type & Name & Description & Size \\ \midrule
%         input  & CLK  & 输入PE模块的时钟信号 & 32b \\
%         input  & RST  & 模块重置寄存器 & 16b \\
%         input   & SCLR   & 同步清零寄存器 & 16b \\
%         input   & A   & 输入参数A & 8b \\
%         input   & B   & 输入参数B & 8b \\
%         output   & Next\_A   & 输出到下一个PE的A & 8b \\
%         output   & Next\_B   & 输出到下一个PE的B & 8b \\
%         output & P & PE的运算结果P & 16b \\ \bottomrule
%     \end{tabular}
%   \end{table}

  
脉动阵列的设计和C模型实现，可以分为两个部分：脉动阵列模块的顶层设计和处理单元的设计。
处理单元(PE)的寄存器：时钟、重置、同步清零、输入参数A、输入参数B、输出给下一级的A、输出给下一级的
B、输出P值。


\subsubsection{算数逻辑单元}
算术逻辑单元是用来运算脉动阵列无法处理的运算的。

\paragraph{批规一化}


\paragraph{全连接}

\paragraph{Relu函数}

%TODO 关于存储Multiple Bank的设计（状态机）
% 11/24 这一段需要重写，可能会搬到上面的某一段
% 本设计中，专门对存储进行了优化，区分开了不同的RAM区域来存储不用的数据，主要由以下几个区域：存储输入和输出数据的
% INRAM和OUTRAM、存储网络数据的NRAM、存储权重的WRAM、存储系统数据的SRAM以及存储临时数据的TRAM。拆分存储的设计
% 主要有以下两大好处：读写的带宽和避免冲突。
% 拆分存储之后，SRAM可以被调整为适当的读写宽度。假设输入和输出的宽度是$X_a \times K$字节,存储网络和权重数据的
% NRAM和WRAM为$X_a \times X_a \times K$字节。如果是用CPU或GPU，且未做优化的情况下，处理器只能按照固定宽度读取
% 数据。

